﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;
using System.Reflection;
using System.IO;
using System.Runtime.InteropServices;

namespace BobcatUtility
{
    /// <summary>
    /// Contains miscellaneous (mostly static) utility functions.
    /// </summary>
    public class Utility
    {
        #region Win32 imports

        [DllImport("user32")]
        public static extern int ClientToScreen(int hwnd, ref Point lpPoint);

        [DllImport("user32")]
        public static extern int GetClientRect(int hwnd, ref Rectangle lpRect);

        #endregion

        #region Public functions

        /// <summary>
        /// Creates a copy of the point passed in.
        /// </summary>
        public static Point copy(Point p)
        {
            return new Point(p.X, p.Y);
        }

        /// <summary>
        /// Fires the event passed in in a thread-safe way. 
        /// </summary><remarks>
        /// This method loops through the targets of the event and invokes each in turn. If the
        /// target supports ISychronizeInvoke (such as forms or controls) and is set to run 
        /// on a different thread, then we call BeginInvoke to marshal the event to the target
        /// thread. If the target does not support this interface (such as most non-form classes)
        /// or we are on the same thread as the target, then the event is fired on the same
        /// thread as this is called from.
        /// </remarks>
        public static void CrossThreadInvoke<T>(EventHandler<T> theEvent, object sender, T args) where T : System.EventArgs
        {
            // Is the event set up?
            if (theEvent == null)
            {
                return;
            }

            // We loop through each of the delegate handlers for this event. For each of 
            // them we need to decide whether to invoke it on the current thread or to
            // make a cross-thread invocation...
            foreach (EventHandler<T> handler in theEvent.GetInvocationList())
            {
                try
                {
                    ISynchronizeInvoke target = handler.Target as ISynchronizeInvoke;
                    if (target == null || target.InvokeRequired == false)
                    {
                        // Either the target is not a form or control, or we are already
                        // on the right thread for it. Either way we can just fire the
                        // event as normal...
                        handler(sender, args);
                    }
                    else
                    {
                        // The target is most likely a form or control that needs the
                        // handler to be invoked on its own thread...
                        target.BeginInvoke(handler, new object[] { sender, args });
                    }
                }
                catch (Exception)
                {
                    // The event handler may have been detached while processing the events.
                    // We just ignore this and invoke the remaining handlers.
                }
            }
        }

        /// <summary>
        /// Returns the rectangle of the client area of the control passed in expressed 
        /// as screen coordinates.
        /// </summary>
        public static Rectangle getScreenBounds(int hWnd)
        {
            Rectangle result = new Rectangle();

            // We find the width and height of the client area...
            Rectangle clientRectangle = new Rectangle();
            GetClientRect(hWnd, ref clientRectangle);

            // We find the upper-left point...
            Point originPoint = new Point(0, 0);
            ClientToScreen(hWnd, ref originPoint);

            // We set the results...
            result.X = originPoint.X;
            result.Y = originPoint.Y;
            result.Width = clientRectangle.Width;
            result.Height = clientRectangle.Height;

            return result;
        }

        public static Image getImageFromResources(string strImageName)
        {
            Assembly assembly = Assembly.GetCallingAssembly();
            string strAssemblyName = assembly.GetName().Name;
            string strResourceName = strAssemblyName + "." + strImageName;
            Stream stream = assembly.GetManifestResourceStream(strResourceName);
            Image image = Image.FromStream(stream);
            return image;
        }

        #endregion
    }
}
